/*
 * @(#)Util.java     14/08/02
 * 
 * Author             Rick Wilson
 * Copyright (c) 2014 Rick Wilson
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of 'Taareekah' nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */



package worldgeneration;

//~--- non-JDK imports --------------------------------------------------------

import world.GenericTerrainMap;

//~--- JDK imports ------------------------------------------------------------

import java.util.regex.Pattern;

import javax.management.JMException;

/**
 *
 * @author rick
 */
public class Util {

    /**
     *
     */
    public static final double	PI_OVER_TWO	= Math.PI / 2.0;

    /**
     *
     * @param str
     * @return
     */
    static public Class<?> getTypeFromString(String str) {
	str	= str.trim();

	// Does it contain anything other then numbers or a decimal point?
	if (Pattern.matches("[\\d]+((([\\.]){1}[\\d]+)|(L))?", str)) {
	    if (str.contains(".")) {
		return Double.TYPE;
	    }

	    if (str.contains("L")) {
		return Long.TYPE;
	    }

	    return Integer.TYPE;
	}

	if (Pattern.matches("^(true|false)$", str.toLowerCase())) {
	    return Boolean.TYPE;
	}

	return str.getClass();
    }

    /**
     *
     * @param map
     * @param np
     * @param radius
     * @throws Exception
     */
    static public void smooth(GenericTerrainMap map, float np, int radius) throws Exception {
	int	size	= map.getSize();

	if ((np < 0) || (np > 1)) {
	    return;
	}

	if (radius == 0) {
	    radius	= 1;
	}

	for (int x = 0; x < size; x++) {
	    for (int y = 0; y < size; y++) {
		int	neighNumber	= 0;
		float	neighAverage	= 0;

		for (int rx = -radius; rx <= radius; rx++) {
		    for (int ry = -radius; ry <= radius; ry++) {
			if ((x + rx < 0) || (x + rx >= size)) {
			    continue;
			}

			if ((y + ry < 0) || (y + ry >= size)) {
			    continue;
			}

			neighNumber++;
			neighAverage	+= map.getValueAtPoint((x + rx), (y + ry));

			// neighAverage += heightData[(x+rx) + (y+ry) * size];
		    }
		}

		neighAverage	/= neighNumber;

		float	cp	= 1 - np;

		map.setValueAtPoint(x, y, neighAverage * np + map.getValueAtPoint(x, y) * cp);
	    }
	}
    }

    /**
     *
     * @param y
     * @param world_size
     * @return
     * @throws Exception
     */
    static public double latitudeNorthHemisphereFloat(float y, int world_size) throws Exception {
	if (world_size < 0) {
	    throw new JMException("The size is negative");
	} else if ((y < 0.0f) || (y >= (float) world_size)) {
	    throw new JMException("Y is negative or greater than world size");
	}

	return PI_OVER_TWO * Math.sin((Math.PI * (double) y) / (2.0 * (double) (world_size - 1)));
    }

    /**
     *
     * @param y
     * @param world_size
     * @return
     * @throws Exception
     */
    static public double latitudeNorthHemisphere(int y, int world_size) throws Exception {
	if (world_size < 0) {
	    throw new JMException("The size is negative");
	} else if ((y < 0) || (y >= world_size)) {
	    throw new JMException("Y is negative or greater than world size");
	}

	return PI_OVER_TWO * Math.sin((Math.PI * (double) y) / (2.0 * (double) (world_size - 1)));
    }

    /**
     *
     * @param y
     * @param world_size
     * @return
     * @throws Exception
     */
    static public double latitudeRadians(int y, int world_size) throws Exception {
	if (world_size < 0) {
	    throw new JMException("The size is negative");
	} else if ((y < 0) || (y >= world_size)) {
	    throw new JMException("Y is negative or greater than world size");
	}

	double	world_size_minus_one	= (double) (world_size - 1);

	return -PI_OVER_TWO * Math.cos((Math.PI * (double) y) / (world_size_minus_one));
    }

    /**
     *
     * @param y
     * @param world_size
     * @return
     * @throws Exception
     */
    static public double latitudeDegrees(int y, int world_size) throws Exception {
	return Math.toDegrees(latitudeRadians(y, world_size));
    }

    /**
     *
     * @param y
     * @param world_size
     * @return
     * @throws Exception
     */
    static public int latitudeWholeDegrees(int y, int world_size) throws Exception {
	return (int) Math.round(latitudeDegrees(y, world_size));
    }

    /**
     * <code>bilinearInterpolation</code> returns the interpolated value at pos
     * given the values in corner_values.
     *
     * @param corner_values
     *          The values of the function at the corners of a square of size square_size,
     *              corner_values[] = {f(0,0), f(square_size,0), f(square_size,square_size), f(0,square_size)}
     *
     * @param square_size
     *          The size of the edges of the square to interpolate within
     *
     * @param x
     *          The x position to find the value of. Must be between 0 <= x <= square_size
     *
     * @param y
     *          The y position to find the value of. Must be between 0 <= x <= square_size
     * @return The value of the function at pos
     */
    public static float bilinearInterpolation(float[] corner_values, float square_size, float x, float y) {	// throws Exception {

	/*
	 * if (square_size <= 0.0) {
	 *   throw new JMException("Square size less than or equal to 0");
	 * }
	 *
	 * if (x < 0.0 || y < 0.0 || x > square_size || y > square_size) {
	 *   throw new JMException("X or Y not within [0, square_size]");
	 *
	 * }
	 */

	// F(x1,y1) * (x2 - x) * (y2 - y)
	float	part1	= corner_values[0] * (square_size - x) * (square_size - y);

	// F(x2,y1) * (x - x1) * (y2 - y)
	float	part2	= corner_values[1] * (x) * (square_size - y);

	// F(x2,y2) * (x - x1) * (y - y1)
	float	part3	= corner_values[2] * (x) * (y);

	// F(x1,y2) * (x2 - x) * (y - y1)
	float	part4	= corner_values[3] * (square_size - x) * (y);

	return (part1 + part2 + part3 + part4) / (square_size * square_size);
    }
}


//~ Formatted by Jindent --- http://www.jindent.com
